<?php

namespace yunj\init\step;

/**
 * 配置文件初始化
 * Class ConfigInit
 * @package yunj\init\step
 */
class ConfigInit extends Step {

    public function handle() {
        $res = $this->initRootYunjDir();
        if ($res == self::RES_SKIP) return self::RES_SKIP;
        $this->handleRootYunjConfigDir();
        return self::RES_SUCCESS;
    }

    /**
     * 初始化 根目录/yunj
     * @return int
     */
    private function initRootYunjDir() {
        $dirPath = YUNJ_PATH;
        // 是否存在
        if (is_dir($dirPath)) {
            // 是否有文件
            if (!is_empty_dir($dirPath)) {
                $res = $this->confirm("针对[{$dirPath}]目录文件系统会自动备份，安全起见您可手动备份一下，确认继续执行？否 将跳过 {$this->desc} 流程");
                if (!$res) {
                    // 初始化gitignore
                    $this->initRootYunjDirGitignore();
                    return self::RES_SKIP;
                }
                // 判断目录是否有写入权限
                dir_writeable_mk($dirPath);
                // 进行数据备份
                $this->info("[{$dirPath}]目录自动备份中...");
                $bkPath = $this->backupRootYunjDir();
                $this->info("[{$dirPath}]目录备份完成\r\n备份文件地址: {$bkPath}");
            }
        }
        // 创建目录 或 判断目录是否有写入权限
        dir_writeable_mk($dirPath);
        // 初始化gitignore
        $this->initRootYunjDirGitignore();
        return self::RES_SUCCESS;
    }

    /**
     * 初始化判断gitignore是否存在，不存在则创建新增
     * @return int
     */
    private function initRootYunjDirGitignore() {
        $gitignorePath = ds_replace(YUNJ_PATH . "/.gitignore");
        if (!file_exists($gitignorePath)) {
            $gitignoreContent = <<<CONTENT
initialized.log
CONTENT;
            if ($fp = @fopen($gitignorePath, 'w')) {
                @fwrite($fp, $gitignoreContent);
                @fclose($fp);
            }
        }
    }

    /**
     * 初始化 根目录/yunj/temp
     * @return int
     */
    private function initRootYunjTempDir() {
        $tempDirPath = ds_replace(YUNJ_PATH . "temp");
        // 创建目录 或 判断目录是否有写入权限
        dir_writeable_mk($tempDirPath);
        // 判断gitignore是否存在，不存在则创建新增
        $gitignorePath = $tempDirPath . ds_replace("/.gitignore");
        if (!file_exists($gitignorePath)) {
            $gitignoreContent = <<<CONTENT
*
!.gitignore
CONTENT;
            if ($fp = @fopen($gitignorePath, 'w')) {
                @fwrite($fp, $gitignoreContent);
                @fclose($fp);
            }
        }
    }

    /**
     * 备份 根目录/yunj
     * @return string   返回备份文件地址
     */
    private function backupRootYunjDir(): string {
        $backupFileList = $this->backupRootYunjDirFileList();
        if (!$backupFileList) return '';
        $this->initRootYunjTempDir();
        $backupDirPath = ds_replace(YUNJ_PATH . "temp/backup/");
        dir_writeable_mk($backupDirPath);
        $filename = date("YmdHis");
        $rootPath = root_path();
        if (extension_loaded("zip")) {
            // 安装了zip扩展
            $zip = new \ZipArchive();
            $zipFilePath = $backupDirPath . $filename . ".zip";
            $zip->open($zipFilePath, \ZipArchive::CREATE);
            foreach ($backupFileList as $backupFile) $zip->addFile($backupFile, str_replace($rootPath, "", $backupFile));
            $zip->close();
            return $zipFilePath;
        } else {
            mkdir($backupDirPath . $filename, 0755, true);
            foreach ($backupFileList as $backupFile) {
                $destFilePath = str_replace($rootPath, $backupDirPath . $filename . DIRECTORY_SEPARATOR, $backupFile);
                file_copy($backupFile, $destFilePath);
            }
            return $backupDirPath . $filename;
        }
    }

    // 需要备份的 根目录/yunj 下的文件列表
    private function backupRootYunjDirFileList(string $path = YUNJ_PATH): array {
        static $fileList = [];
        $path = ds_replace($path);
        if (substr($path, -1) === DIRECTORY_SEPARATOR) $path = substr($path, 0, -1);
        if (is_dir($path)) {
            $fileArr = scandir($path);
            foreach ($fileArr as $file) {
                if (in_array($file, [".", "..", "temp", ".gitignore"])) continue;
                $filePath = $path . DIRECTORY_SEPARATOR . $file;
                if (is_file($filePath)) {
                    $fileList[] = $filePath;
                } else {
                    self::backupRootYunjDirFileList($filePath);
                }
            }
        } else {
            $fileList[] = $path;
        }
        return $fileList;
    }

    /**
     * 处理 根目录/yunj/config
     */
    private function handleRootYunjConfigDir(): void {
        $configFileDir = ds_replace(YUNJ_PATH ."config");
        $this->info("对目录[{$configFileDir}]下配置文件进行处理，此操作不会破坏已配置数据\r\n处理中...");
        $vendorConfigFileDir = ds_replace(YUNJ_VENDOR_SRC_PATH."config");
        $vendorConfigFileContentDir = ds_replace(YUNJ_VENDOR_SRC_PATH."init/config_file_content");
        $vendorConfigFileContentFileArr = scandir($vendorConfigFileContentDir);
        foreach ($vendorConfigFileContentFileArr as $configFileName) {
            if ($configFileName === "." || $configFileName === "..") continue;

            $vendorConfigFilePath = $vendorConfigFileDir . ds_replace("/{$configFileName}");
            $configFilePath = $configFileDir . ds_replace("/{$configFileName}");
            if (is_file($configFilePath)) {
                $vendorConfigFileContent = include $vendorConfigFileContentDir . ds_replace("/{$configFileName}");
                // 合并
                if (is_array($vendorConfigFileContent)) {
                    $this->mergeRootYunjConfigFile($vendorConfigFilePath, $configFilePath, $vendorConfigFileContent);
                    $this->info("配置文件[{$configFilePath}] 已合并");
                }
                continue;
            }
            // 新增
            file_copy($vendorConfigFilePath, $configFilePath);
            $this->info("配置文件[{$configFilePath}] 已新增");
        }
    }

    /**
     * 合并 根目录/yunj/config 下的文件
     * @param string $sourcePath [源文件地址]
     * @param string $destPath [目标文件地址]
     * @param array $sourceConfigContent [源文件合并内容]
     */
    private function mergeRootYunjConfigFile(string $sourcePath, string $destPath, $sourceConfigContent): void {
        $sourceConfig = include $sourcePath;
        $destConfig = include $destPath;
        $sourceConfigKeys = array_keys($sourceConfig);
        $destConfigKeys = array_keys($destConfig);
        $diffKeys = array_diff($sourceConfigKeys, $destConfigKeys);
        if (!$diffKeys) return;
        $diffConfigContent = "";
        foreach ($diffKeys as $key) {
            if (!isset($sourceConfigContent[$key])) {
                $configKey = substr($sourcePath, strrpos($sourcePath, DIRECTORY_SEPARATOR) + 1, -4) . "." . $key;
                throw new \RuntimeException("配置[{$configKey}]无配置默认内容，请联系我们");
            }
            $diffConfigContent .= "\r\n{$sourceConfigContent[$key]}\r\n";
        }
        if (!$diffConfigContent) return;
        $destContent = file_get_contents($destPath);
        // 获取最后一个]并替换后面的内容为空
        $destContent = preg_replace("/(?<=\])(?![\w\W]*\])[\w\W]*/", '', $destContent);
        // 截取最后一个字符前的内容+拼接缺的配置内容+];
        $destContent = substr($destContent, 0, -1) . "\r\n{$diffConfigContent}\r\n];";
        file_put_contents($destPath, $destContent);
    }

}